function fdatasync(fd, callback) {
const req = new FSReqCallback();
req.oncomplete = makeCallback(callback);
+
+ if (permission.isEnabled()) {
+ callback(new ERR_ACCESS_DENIED('fdatasync API is disabled when Permission Model is enabled.'));
+ return;
+ }
binding.fdatasync(fd, req);
}
* @returns {void}
*/
function fdatasyncSync(fd) {
+ if (permission.isEnabled()) {
+ throw new ERR_ACCESS_DENIED('fdatasync API is disabled when Permission Model is enabled.');
+ }
binding.fdatasync(fd);
}
function fsync(fd, callback) {
const req = new FSReqCallback();
req.oncomplete = makeCallback(callback);
+ if (permission.isEnabled()) {
+ callback(new ERR_ACCESS_DENIED('fsync API is disabled when Permission Model is enabled.'));
+ return;
+ }
binding.fsync(fd, req);
}
* @returns {void}
*/
function fsyncSync(fd) {
+ if (permission.isEnabled()) {
+ throw new ERR_ACCESS_DENIED('fsync API is disabled when Permission Model is enabled.');
+ }
binding.fsync(fd);
}
mtime = toUnixTimestamp(mtime, 'mtime');
callback = makeCallback(callback);
+ if (permission.isEnabled()) {
+ callback(new ERR_ACCESS_DENIED('futimes API is disabled when Permission Model is enabled.'));
+ return;
+ }
+
const req = new FSReqCallback();
req.oncomplete = callback;
binding.futimes(fd, atime, mtime, req);
* @returns {void}
*/
function futimesSync(fd, atime, mtime) {
+ if (permission.isEnabled()) {
+ throw new ERR_ACCESS_DENIED('futimes API is disabled when Permission Model is enabled.');
+ }
+
binding.futimes(
fd,
toUnixTimestamp(atime, 'atime'),
}, {
code: 'ERR_ACCESS_DENIED',
});
+}
+
+// fs.utimes with read-only fd
+{
+ assert.throws(() => {
+ // blocked file is allowed to read
+ const fd = fs.openSync(blockedFile, 'r');
+ const date = new Date();
+ date.setFullYear(2100,0,1);
+
+ fs.futimes(fd, date, date, common.expectsError({
+ code: 'ERR_ACCESS_DENIED',
+ }));
+ fs.futimesSync(fd, date, date);
+ }, {
+ code: 'ERR_ACCESS_DENIED',
+ });
+}
+
+// fs.fdatasync with read-only fd
+{
+ assert.throws(() => {
+ // blocked file is allowed to read
+ const fd = fs.openSync(blockedFile, 'r');
+ fs.fdatasync(fd, common.expectsError({
+ code: 'ERR_ACCESS_DENIED',
+ }));
+ fs.fdatasyncSync(fd);
+ }, {
+ code: 'ERR_ACCESS_DENIED',
+ });
+}
+
+// fs.fsync with read-only fd
+{
+ assert.throws(() => {
+ // blocked file is allowed to read
+ const fd = fs.openSync(blockedFile, 'r');
+ fs.fsync(fd, common.expectsError({
+ code: 'ERR_ACCESS_DENIED',
+ }));
+ fs.fsyncSync(fd);
+ }, {
+ code: 'ERR_ACCESS_DENIED',
+ });
}
\ No newline at end of file
'unwatchFile',
...syncAndAsyncAPI('lstat'),
...syncAndAsyncAPI('realpath'),
- // fd required methods
+ // File descriptor–based metadata operations
+ //
+ // The kernel does not allow opening a file descriptor for an inode
+ // with write access if the inode itself is read-only. However, it still
+ // permits modifying the inode’s metadata (e.g., permission bits, ownership,
+ // timestamps) because you own the file. These changes can be made either
+ // by referring to the file by name (e.g., chmod) or through any existing
+ // file descriptor that identifies the same inode (e.g., fchmod).
+ //
+ // If the kernel required write access to change metadata, it would be
+ // impossible to modify the permissions of a file once it was made read-only.
+ // For that reason, syscalls such as fchmod, fchown, and futimes bypass
+ // the file descriptor’s access mode. Even a read-only ('r') descriptor
+ // can still update metadata. To prevent unintended modifications,
+ // these APIs are therefore blocked by default when permission model is
+ // enabled.
...syncAndAsyncAPI('close'),
...syncAndAsyncAPI('fchown'),
...syncAndAsyncAPI('fchmod'),